using System.Collections.Generic;
using System;
using Acme.Collections;
using Control;

using static Point;
using static Pair<int, string>;
using static Point3D;

using static PointStruct;

using static MySeasons;
using static SomeRootVegetable;

using static MyColor;
using static Squares;

using static StaticEntity;

using static Expression;

using static OverloadingExample;

using static MyList<string>;

using DelegateTest;

using System.Threading.Tasks;
using System.Net.Http;

using AttributeTest;

using mynamespace.bankaccount;

class Example {

    public static void testBankAccount(){
        BankAccount.testBankAccount();
        Console.WriteLine("testBankAccount done.");
    }

    /// <summary>  测试类属性（注解）
    public static void testAttribute(){
        Type widgetType = typeof(Widget);
        object[] widgetClassAttributes = widgetType.GetCustomAttributes(typeof(HelpAttribute), false);
        if(widgetClassAttributes.Length > 0) {
            HelpAttribute attr = (HelpAttribute)widgetClassAttributes[0];
            Console.WriteLine($"Widget class help URL : {attr.Url} - Related topic: {attr.Topic}");
        }
        
        /// 方法上的属性
        System.Reflection.MethodInfo displayMethod = widgetType.GetMethod(nameof(Widget.Display));
        object[] displayMethodAttributes = displayMethod.GetCustomAttributes(typeof(HelpAttribute), false);
        if(displayMethodAttributes.Length > 0) {
            HelpAttribute attr = (HelpAttribute)displayMethodAttributes[0];
            Console.WriteLine($"Display method help URL : {attr.Url} - Related Topic is {attr.Topic}");
        }        
    }

    public static void testAsync(){
        Task<int> _task = RetrieveDocsHomePage();
        Console.WriteLine($"Content.Length is {_task.Result}");
    }

    /// <summary> 测试 async/await的使用
    public static async Task<int> RetrieveDocsHomePage(){
        var client = new HttpClient();
        byte[] content = await client.GetByteArrayAsync("http://docs.microsoft.com/");
        Console.WriteLine($"{nameof(RetrieveDocsHomePage)}:Finished downloading..");
        return content.Length;
    }

    /// <summary> 测试委托
    public static void testDelegate(){
        DelegateTest.DelegateExample.test();
    }

    /// <summary> 测试数组
    public static void testArray(){

        int[] a = new int[10];
        for(int i=0; i< a.Length; i++) {
            a[i] = i * i;
        }
        for(int i=0; i<a.Length; i++) {
            Console.Write($"a[{i}] = {a[i]}\t");
        }
        Console.WriteLine();

        int[] a1 = new int[10];
        int[,] a2 = new int[10, 5];
        int[,,] a3 = new int[10,5,2];

        //多维数组的元素数组可以是长度不一样的
        int[][] a4 = new int[3][];
        a4[0] = new int[4];
        a4[1] = new int[3];
        a4[2] = new int[10];

        for(int i=0; i<a4.Length; i++) {
            Console.WriteLine($"row = {i}, a4[{i}].Length = {a4[i].Length}");
        }

        int[] a5 = new int[]{1, 2, 3};
        for(int i=0; i<a5.Length; i++) {
            Console.WriteLine($"a5[{i}] = {a5[i]}");
        }
        int[] a6 = { 1, 2, 3 };
        Console.WriteLine("a6.item is");
        foreach(int item in a6){
            Console.Write(item + " ");
        }
        Console.WriteLine();
    }

    private static int s_changeCount;

    public static void ListChanged(object sender, EventArgs s) {
        s_changeCount++;
    }

    /// <summary> 测试类的事件属性， 使用系统的EventHandler
    public static void testEventHandler(){
        var names = new MyList<string>();
        names.Changed += new EventHandler(ListChanged);
        names.Add("Lize");
        names.Add("Martha");
        names.Add("Beth");
        Console.WriteLine($"s_changeCount:{s_changeCount}");
    }

    /// <summary> 测试重栽
    public static void testOverloading(){
        OverloadingExample.UsageExample();
    }

    /// <summary> 测试继承，多态， 虚函数， 抽象类，抽象方法
    /// 以下程序使用 Expression 类根据不同的 x 和 y 值计算表达式 x * (y + 2)。
    public static void testExpression(){
        //Expression e = new Operation(new VariableReference("x"), '+', new Constant(3));
        Expression e = new Operation(new VariableReference("x"),
        '*',
        new Operation(new VariableReference("y"),
            '+', 
            new Constant(2)));

        Dictionary<string, object> vars = new Dictionary<string, object>();
        vars["x"] = 3;
        vars["y"] = 5;
        Console.WriteLine($"when x = 3 and y = 5, then expression x*(y+2) = ");
        Console.WriteLine(e.Evaluate(vars));

        vars["x"] = 1.5;
        vars["y"] = 9;
        Console.WriteLine($"when x = 1.5 and y = 9, then expression x*(y+2) = ");
        Console.WriteLine(e.Evaluate(vars));
    }

    /// <summary> 测试类的成员方法和静态方法
    public static void testStaticEntity(){

        StaticEntity.SetNextSerialNo(1000);
        StaticEntity e1 = new StaticEntity();
        StaticEntity e2 = new StaticEntity();
        Console.WriteLine(e1.GetSerialNo());
        Console.WriteLine(e2.GetSerialNo());
        Console.WriteLine(StaticEntity.GetNextSerialNo());
    }

    public static void testLocalParams(){
        Squares.WriteSquares();
    }

    /// <summary> 测试参数数组，可变参数params
    public static void testFunctionParamsKey(){

        int x = 3;
        int y = 4;
        int z = 5;
        // Write 和 WriteLine 方法是参数数组用法的典型示例。 
        // Console.WriteLine("x={0}, y={1}, z = {2}", x, y, z);

        string s= "x={0}, y= {1} z= {2}";
        Object[] args = new Object[3];
        args[0] = x;
        args[1] = y;
        args[2] = z;
        Console.WriteLine(s, args);
        //WriteLines的参数原型如下： 
        //public static void WriteLine(string format, params object?[]? arg);
    }

    /// <summary> 测试参数传递时， 使用out关键字，接受函数的返回引用参数
    public static void testFunctionOutParam(){
        Divide(10, 3, out int res, out int rem);
        Console.WriteLine($"after divide, the res is {res} and rem is {rem}");
    }

    private static void Divide(int x, int y, out int result, out int remainder) {
        result = x/ y;
        remainder = x % y;
    }

    /// <summary> 测试Swap使用ref关键字表示引用参数
    public static void testFunctionRefParam(){
        int i  = 1;
        int j = 2;
        Console.WriteLine($"before swap : i =  {i}, j = {j}");
        Swap(ref i, ref j);
        Console.WriteLine($"after swap : i =  {i}, j = {j}");
    }


    private static void Swap(ref int x, ref int y) {
        int temp = x; //
        x = y;
        y = temp;
    }

    public static void testReadOnlyField(){
        Console.WriteLine($"Black color is {MyColor.Black.ToString()}");
    }

    /**
    * 测试元祖
    ***/
    public static void test_tuple(){
        (double Sum, int Count) t2 = (4.5, 3);
        Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
    }

    /// <summary>测试可空类型
    public static void testNullalbe(){
        //#nullable
        int? optinalInt = default;
        Console.WriteLine("optionalInt default is " + optinalInt);
        optinalInt = 5;
        //#nullable        
        string? optionalText =default;
        Console.WriteLine("optionalText default is " + optionalText);
        optionalText = "Hello world.";
        Console.WriteLine("optionalText : " + optionalText + ", optionalInt is" + optinalInt);
    }

    /// <summary> 测试enum
    public static void test_enums() {
        var turnip = SomeRootVegetable.Turnip;
        var spring = MySeasons.Spring;

        var startingOnEquinox = MySeasons.Spring | MySeasons.Autumn;

        var theYear = MySeasons.All;

        Console.WriteLine("The year is " + theYear + ", startingOnEquinox : " + startingOnEquinox + ", turnip is " + turnip + ", spring is " + spring);
    }

    /// <summary> 测试接口和继承
    public static void test_comboBox(){
        ComboBoxImpl combo= new ComboBoxImpl();
        combo.SetText("great BOX");
        string[] items = new string[] { "box1", "box2", "box3"};
        combo.SetItems(items);
        combo.Paint();
    }

    /// <summary> 测试结构体
    public static void test_pointstruct(){

        PointStruct pointStruct = new PointStruct(1,2);
        Console.WriteLine("pointStruct : " + pointStruct.X +", " + pointStruct.Y);
    }

    /// <summary> 测试类
    public static void test_point3d(){

        Point3D p3d = new Point3D(1,2,3);
        Console.WriteLine("Point3D : " + p3d.X + ", " + p3d.Y + ", " + p3d.Z);
    }

    /// <summary> 测试范型
    public static void testStack(){

        var mStack = new Acme.Collections.Stack<int>();
        mStack.Push(1);
        mStack.Push(10);
        mStack.Push(100);
 
        Console.WriteLine("ele: " + mStack.Pop());
        Console.WriteLine("ele: " + mStack.Pop());
        Console.WriteLine("ele: " + mStack.Pop());
    }

    ///测试类成员属性
    public static void test_Point_Pair(){
        var p1 = new Point(0, 0);
        var p2 = new Point(10, 20);

        Console.WriteLine("p1 : " + p1.ToString());

        var pair = new Pair<int, string>(1, "two");
        int i = pair.First;
        string s = pair.Second;
        Console.WriteLine("i: " + i + ", s : " + s);
    }
}